//
// Created by HP on 2022/2/2.
//

#include "movement_controller.h"

#include <cmath>

namespace tmc {

    void MovementController::moveInPlaneXZ(
            GLFWwindow *window, float dt, TmcGameObject &gameObject) {
        glm::vec3 rotate{0};

        // 计算鼠标
        double xPos, yPos;
        auto lveWindow = reinterpret_cast<TmcWindow*>(glfwGetWindowUserPointer(window));
        lveWindow->getCursorPos(&xPos, &yPos);
        glm::vec2 newCursor{xPos, yPos};
        auto cursorMove = newCursor - cursor;
        if (cursorMove.x > std::numeric_limits<float>::epsilon() ||
        cursorMove.x < -std::numeric_limits<float>::epsilon()) {
            rotate.y += cursorMove.x * 30.f;
        }
        if (cursorMove.y > std::numeric_limits<float>::epsilon() ||
        cursorMove.y < -std::numeric_limits<float>::epsilon()) {
            rotate.x += cursorMove.y * 30.f;
        }

        cursor = newCursor;

        if (glm::dot(rotate, rotate) > std::numeric_limits<float>::epsilon()) {
            gameObject.transform.rotation += lookSpeed * dt * rotate;
        }
        // 防止在一个方向上不断旋转导致溢出
        gameObject.transform.rotation.y = glm::mod(gameObject.transform.rotation.y, glm::two_pi<float>());

        const float c2 = glm::cos(gameObject.transform.rotation.x);
        const float s2 = glm::sin(gameObject.transform.rotation.x);
        const float c1 = glm::cos(gameObject.transform.rotation.y);
        const float s1 = glm::sin(gameObject.transform.rotation.y);
        const float x = c2 * s1;
        const float y = -s2;
        const float z = c1 * c2;
        const glm::vec3 forwardDir{x, y, z};
        const glm::vec3 rightDir{z, 0.f, -x};

        glm::vec3 moveDir{0.f};
        if (glfwGetKey(window, keys.moveForward)  == GLFW_PRESS) moveDir += forwardDir;
        if (glfwGetKey(window, keys.moveBackward) == GLFW_PRESS) moveDir -= forwardDir;
        if (glfwGetKey(window, keys.moveRight)    == GLFW_PRESS) moveDir += rightDir;
        if (glfwGetKey(window, keys.moveLeft)     == GLFW_PRESS) moveDir -= rightDir;

        if (glm::dot(moveDir, moveDir) > std::numeric_limits<float>::epsilon()) {
            gameObject.transform.translation += moveSpeed * dt * moveDir;
        }
    }

}